package com.evil.application.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.evil.application.pojo.dto.order.OrderBaseReqDTO;
import com.evil.application.pojo.entity.ApplicationProcessNode;
import com.evil.common.application.dto.process.node.NodeBaseDTO;
import com.evil.common.application.util.ApplicationRedisKeyUtil;
import com.evil.common.core.constant.RedisConstant;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.CacheMapperUtil;
import com.evil.common.core.util.StreamUtil;
import org.apache.ibatis.annotations.Param;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 应用流程节点表
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
public interface ApplicationProcessNodeMapper extends BaseMapper<ApplicationProcessNode> {

    Optional<ApplicationProcessNode> isExistById(@Param("id") Long id, @Param("filterDeleted") boolean filterDeleted);

    default Optional<ApplicationProcessNode> isExistById_Cache(Long id, boolean filterDeleted) {
        return CacheMapperUtil.cacheById(
                id,
                ApplicationProcessNode.class,
                e -> this.findById(id, filterDeleted),
                ApplicationRedisKeyUtil::requestUuidControlKey,
                RedisConstant.REQUEST_UUID_EXPIRE_IN_SECOND
        );
    }

    default ApplicationProcessNode findById(Long id, boolean filterDeleted) {
        return this.isExistById(id, filterDeleted).orElseThrow(() -> new BusinessException(RCodeEnum.APPLICATION_FORM_CONTROL_NOT_EXIST));
    }

    default ApplicationProcessNode findById_Cache(Long id, boolean filterDeleted) {
        return this.isExistById_Cache(id, filterDeleted).orElseThrow(() -> new BusinessException(RCodeEnum.APPLICATION_FORM_CONTROL_NOT_EXIST));
    }

    Optional<ApplicationProcessNode> isExistStartNodeByProcessId(Long processId);

    default ApplicationProcessNode findStartNodeByProcessId(Long processId) {
        return this.isExistStartNodeByProcessId(processId).orElseThrow(() -> new BusinessException(RCodeEnum.APPLICATION_PROCESS_NODE_NOT_EXIST));
    }

    Optional<ApplicationProcessNode> isExistEndNodeByProcessId(Long processId);

    default ApplicationProcessNode findEndNodeByProcessId(Long processId) {
        return this.isExistEndNodeByProcessId(processId).orElseThrow(() -> new BusinessException(RCodeEnum.APPLICATION_PROCESS_NODE_NOT_EXIST));
    }

    List<ApplicationProcessNode> findStartNodeByProcessIds(@Param("processIds") Collection<Long> processIds);

    List<ApplicationProcessNode> findByIds(@Param("ids") Collection<Long> ids, @Param("filterDeleted") boolean filterDeleted);

    default List<ApplicationProcessNode> findByIds_Cache(Collection<Long> ids, boolean filterDeleted) {
        return CacheMapperUtil.cacheByIds(
                ids,
                filterDeleted,
                ApplicationProcessNode.class,
                this::findByIds,
                ApplicationProcessNode::getProcessId,
                ApplicationProcessNode::getIsDeleted,
                null,
                ApplicationRedisKeyUtil::requestUuidControlKeyMap,
                RedisConstant.REQUEST_UUID_EXPIRE_IN_SECOND
        );
    }

    List<ApplicationProcessNode> findByParentNodeId(@Param("parentNodeId") Long parentNodeId, @Param("filterDeleted") boolean filterDeleted);

    List<ApplicationProcessNode> findByParentNodeIds(@Param("parentNodeIds") Collection<Long> parentNodeIds, @Param("filterDeleted") boolean filterDeleted);

    List<ApplicationProcessNode> findByProcessId(@Param("processId") Long processId, @Param("filterDeleted") boolean filterDeleted);

    List<ApplicationProcessNode> findByProcessIds(@Param("processIds") Collection<Long> processIds, @Param("filterDeleted") boolean filterDeleted);

    default Map<Long, ApplicationProcessNode> findMapByIds(Collection<Long> ids, boolean filterDeleted) {
        return StreamUtil.toMapK(this.findByIds(ids, filterDeleted), ApplicationProcessNode::getNodeId);
    }

    List<ApplicationProcessNode> findOrderNodes(OrderBaseReqDTO orderBaseReqDTO);

    Optional<NodeBaseDTO> isExistBaseById(@Param("id") Long id, @Param("filterDeleted") boolean filterDeleted);

    default NodeBaseDTO findBaseById(Long id, boolean filterDeleted) {
        return this.isExistBaseById(id, filterDeleted).orElseThrow(() -> new BusinessException(RCodeEnum.APPLICATION_PROCESS_NODE_NOT_EXIST));
    }

    List<NodeBaseDTO> findBaseByIds(@Param("ids") Collection<Long> ids, @Param("filterDeleted") boolean filterDeleted);

    default Map<Long, NodeBaseDTO> findBaseMapByIds(Collection<Long> ids, boolean filterDeleted) {
        return StreamUtil.toMapK(this.findBaseByIds(ids, filterDeleted), NodeBaseDTO::getNodeId);
    }
}